﻿namespace MicroCloud.Extensions
{
    /// <summary>
    /// 服务提供者接口辅助扩展方法类
    /// </summary>
    public static partial class IServiceProviderExtensions
    {
        /// <summary>
        /// 从服务提供者中获取系统配置选项信息
        /// </summary>
        /// <param name="provider">服务提供者</param>
        /// <returns>系统配置选项信息</returns>
        public static MicroCloudOptions GetMicroCloudOptions(this IServiceProvider provider)
        {
            //return provider.GetService<IOptions<MicroCloudOptions>>()?.Value;    //为支持热重载，优先从单例获取实例。
            var options = Singleton<MicroCloudOptions>.Instance;
            if (options == null)
            {
                var configuration = provider.GetService<IConfiguration>();
                if (configuration != null)
                {
                    options = new();
                    new MicroCloudOptionsSetup(configuration).Configure(options);
                }
            }
            return options;
        }

        /// <summary>
        /// 从服务提供者获取 <see cref="IUnitOfWork"/>
        /// </summary>
        /// <param name="provider">服务提供者</param>
        /// <param name="transaction">启用事务</param>
        /// <param name="immediate">立即开启事务，transaction=true 时有效。</param>
        /// <param name="isolationLevel">事务隔离级别，transaction=true 时有效。</param>
        /// <returns></returns>
        public static IUnitOfWork GetUnitOfWork(this IServiceProvider provider, bool transaction = false, bool immediate = false, IsolationLevel? isolationLevel = null)
        {
            IUnitOfWork unitOfWork = provider.GetRequiredService<IUnitOfWork>();
            if (transaction)
            {
                unitOfWork.EnableTransaction();
                if (immediate)
                {
                    unitOfWork.BeginOrUseTransaction(isolationLevel);
                }
            }

            return unitOfWork;
        }

        /// <summary>
        /// 异步从服务提供者获取 <see cref="IUnitOfWork"/>
        /// </summary>
        /// <param name="provider">服务提供者</param>
        /// <param name="transaction">启用事务</param>
        /// <param name="immediate">立即开启事务，transaction=true 时有效。</param>
        /// <param name="isolationLevel">事务隔离级别，transaction=true 时有效。</param>
        /// <returns></returns>
        public static async Task<IUnitOfWork> GetUnitOfWorkAsync(this IServiceProvider provider, bool transaction = false, bool immediate = false, IsolationLevel? isolationLevel = null)
        {
            IUnitOfWork unitOfWork = provider.GetRequiredService<IUnitOfWork>();
            if (transaction)
            {
                unitOfWork.EnableTransaction();
                if (immediate)
                {
                    await unitOfWork.BeginOrUseTransactionAsync(isolationLevel);
                }
            }

            return unitOfWork;
        }

        /// <summary>
        /// 获取指定实体类型的上下文对象
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="provider"></param>
        /// <returns></returns>
        public static IDbContext GetDbContext<TEntity, TKey>(this IServiceProvider provider) where TEntity : IEntity<TKey>
        {
            IUnitOfWork unitOfWork = provider.GetUnitOfWork();
            return unitOfWork.GetEntityDbContext<TEntity, TKey>();
        }

        /// <summary>
        /// 获取所有模块信息
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public static PackBase[] GetAllPacks(this IServiceProvider provider)
        {
            PackBase[] packs = provider.GetServices<PackBase>().OrderBy(m => m.Level).ThenBy(m => m.OrderNo).ThenBy(m => m.GetType().FullName).ToArray();
            return packs;
        }

        /// <summary>
        /// 获取当前用户
        /// </summary>
        /// <param name="provider">服务提供者</param>
        /// <returns></returns>
        public static ClaimsPrincipal GetCurrentUser(this IServiceProvider provider)
        {
            try
            {
                IPrincipal user = provider.GetService<IPrincipal>();
                return user as ClaimsPrincipal;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 获取指定类型的当前组织机构编号
        /// </summary>
        /// <param name="provider">服务提供者</param>
        /// <returns></returns>
        public static T GetCurrentOrganizationId<T>(this IServiceProvider provider)
        {
            try
            {
                IPrincipal user = provider.GetService<IPrincipal>();
                if (user == null)
                {
                    return default;
                }
                return user.Identity.GetCurrentOrganizationId<T>();
            }
            catch (System.Exception)
            {
                return default;
            }
        }

        /// <summary>
        /// 获取当前组织机构编号
        /// </summary>
        /// <param name="provider">服务提供者</param>
        /// <returns></returns>
        public static string GetCurrentOrganizationId(this IServiceProvider provider)
        {
            try
            {
                IPrincipal user = provider.GetService<IPrincipal>();
                if (user == null)
                {
                    return null;
                }
                return user.Identity.GetCurrentOrganizationId();
            }
            catch (System.Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 获取指定类型的当前部门机构编号
        /// </summary>
        /// <param name="provider">服务提供者</param>
        /// <returns></returns>
        public static T GetCurrentDepartmentId<T>(this IServiceProvider provider)
        {
            try
            {
                IPrincipal user = provider.GetService<IPrincipal>();
                if (user == null)
                {
                    return default;
                }
                return user.Identity.GetCurrentDepartmentId<T>();
            }
            catch (System.Exception)
            {
                return default;
            }
        }

        /// <summary>
        /// 获取当前部门机构编号
        /// </summary>
        /// <param name="provider">服务提供者</param>
        /// <returns></returns>
        public static string GetCurrentDepartmentId(this IServiceProvider provider)
        {
            try
            {
                IPrincipal user = provider.GetService<IPrincipal>();
                if (user == null)
                {
                    return null;
                }
                return user.Identity.GetCurrentDepartmentId();
            }
            catch (System.Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 框架初始化
        /// <para>适用于非AspNetCore环境</para>
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public static IServiceProvider UseMicroCloud(this IServiceProvider provider)
        {
            ILogger logger = provider.GetLogger(typeof(IServiceProviderExtensions));
            logger.LogInformation("开始执行系统框架初始化");

            Stopwatch watch = Stopwatch.StartNew();

            PackBase[] packs = provider.GetAllPacks();
            logger.LogInformation("获取到 {length} 个模块(Pack)需要加载", packs.Length);
            foreach (PackBase pack in packs)
            {
                pack.UsePack(provider);
                logger.LogInformation("模块 {type} 加载完成", pack.GetType());
            }

            watch.Stop();
            logger.LogInformation("系统框架初始化完成，耗时：{elapsed}。", watch.Elapsed);

            //打印一个MicroCloud的启动彩蛋
            ConsoleHelper.WriteLine($@"
                    _                  ___ _                 _ 
              /\/\ (_) ___ _ __ ___   / __\ | ___  _   _  __| |
             /    \| |/ __| '__/ _ \ / /  | |/ _ \| | | |/ _` |
            / /\/\ \ | (__| | | (_) / /___| | (_) | |_| | (_| |
            \/    \/_|\___|_|  \___/\____/|_|\___/ \__,_|\__,_|", ConsoleColor.DarkRed);

            ConsoleHelper.WriteLine($@"                      科技改变未来 · 数据传承价值                   
            ", ConsoleColor.DarkYellow);

            return provider;
        }

    }
}
